﻿namespace OfficeClip.OpenSource.StyleFix.Drivers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;

    public class LayoutRules : StyleCopRules
    {

        internal void SA1503_CurlyBracketsMustNotBeOmittedTest(ref List<SFWorkingLine> workingLines)
        {
            var saObjects = new List<SAObject>();
            Decimal lineNumberOffset = 0;
            for (int i = 0; i < workingLines.Count; i++)
            {
                SFWorkingLine workingLine = workingLines[i];
                if (IsLineViolated(workingLine, "SA1503"))
                {
                    SAObject saob = workingLine.Violations.Find(sao => sao.ErrorId == "SA1503");
                    string check = workingLine.Line;
                    int lineBreakIndex = 0 ;
                    int statementStartline = i;

                    string statement = saob.Description.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[4];

                    var match = Regex.Match(check, @"(\s*)" + statement + @"\s*\(");

                    while (!match.Success && statementStartline > 0)
                    {
                        check = workingLines[statementStartline - 1].Line + Environment.NewLine + check;
                        lineBreakIndex += workingLines[statementStartline - 1].Line.Length;
                        match = Regex.Match(check, @"(\s*)" + statement + @"\s*\(");
                        statementStartline--;
                    }
                    
                    if (match.Success)
                    {
                        string whitespace = match.Groups[1].Value;
                        int index = match.Index + match.Length;
                        //if the statement is on the same line as the target then we need to add a line break after the statement
                        if (index > lineBreakIndex)
                        {
                            CharacterPoint endIndex = CodeUtils.FindMatchingParenthesis(workingLines, i, index - lineBreakIndex);
                            i = endIndex.LineNumber;
                            workingLine = workingLines[i];
                            var newWorkingLine = new SFWorkingLine(i + 1, whitespace + "    " + workingLine.Line.Substring(endIndex.Position + 1).Trim(), false, saObjects);
                            workingLine.Line = workingLine.Line.Remove(endIndex.Position + 1);
                            workingLines.Insert(i + 1, newWorkingLine);
                            lineNumberOffset++;
                            i++;
                        }
                        int lineOffset = 0;
                        if (workingLines[i].Line.Contains('('))
                        {
                            CharacterPoint end = CodeUtils.FindMatchingParenthesis(workingLines, i, workingLines[i].Line.IndexOf('('));
                            lineOffset = end.LineNumber - i;
                        }
                        workingLines.Insert(i + lineOffset + 1, new SFWorkingLine(i + 2, whitespace + "}", false, saObjects));
                        workingLines.Insert(i, new SFWorkingLine(i, whitespace + "{", false, saObjects));
                        lineNumberOffset += 2;
                        i++;
                    }
                }
                workingLine.LineNo += lineNumberOffset;
            }
        }

        internal void SA1505_AnOpeningCurlyBracketMustNotBeFollowedByABlankLine(ref List<SFWorkingLine> workingLines)
        {
            Decimal lineNumberOffset = 0;
            for (int i = 0; i < workingLines.Count; i++)
            {
                SFWorkingLine workingLine = workingLines[i];
                workingLine.LineNo -= lineNumberOffset;
                if (IsLineViolated(workingLine, "SA1505"))
                {
                    workingLines.RemoveAt(i + 1);
                    lineNumberOffset++;
                }
            }
        }

        internal void SA1513_ClosingCurlyBracketMustBeFollowedByBlankLine(ref List<SFWorkingLine> workingLines)
        {
            var saObjects = new List<SAObject>();
            Decimal lineNumberOffset = 0;
            for (int i = 0; i < workingLines.Count; i++)
            {
                SFWorkingLine workingLine = workingLines[i];
                workingLine.LineNo += lineNumberOffset;
                if (IsLineViolated(workingLine, "SA1513"))
                {
                    workingLines.Insert(i + 1, new SFWorkingLine(i, string.Empty, false, saObjects));
                    lineNumberOffset++;
                    i++;
                }
            }
        }

        internal void SA1515_SingleLineCommentMeBePreceededByABlankLine(ref List<SFWorkingLine> workingLines)
        {
            var saObjects = new List<SAObject>();
            Decimal lineNumberOffset = 0;
            for (int i = 0; i < workingLines.Count; i++)
            {
                SFWorkingLine workingLine = workingLines[i];
                workingLine.LineNo += lineNumberOffset;
                if (IsLineViolated(workingLine, "SA1515"))
                {
                    workingLines.Insert(i, new SFWorkingLine(i, string.Empty, false, saObjects));
                    lineNumberOffset++;
                    i++;
                }
            }
        }

        internal void SA1516_ElementsMustBeSeparatedByBlankLine(ref List<SFWorkingLine> workingLines)
        {
            var saObjects = new List<SAObject>();
            Decimal lineNumberOffset = 0;
            for (int i = 0; i < workingLines.Count; i++)
            {
                SFWorkingLine workingLine = workingLines[i];
                workingLine.LineNo += lineNumberOffset;
                if (IsLineViolated(workingLine, "SA1516"))
                {
                    workingLines.Insert(i, new SFWorkingLine(i, string.Empty, false, saObjects));
                    lineNumberOffset++;
                    i++;
                }
            }
        }
    }
}
